/*
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2021-07-01     andy       the first version
 */

#include <rtthread.h>

#include "mainConfig.h"

#include "modbus485.h"


#define LOG_TAG     "modbus485"        // 该模块对应的标签。不定义时，默认：NO_TAG
#define LOG_LVL     LOG_LVL_DBG   // 该模块对应的日志输出级别。不定义时，默认：调试级别
#include <ulog.h>                 // 必须在 LOG_TAG 与 LOG_LVL 下面




sensor_Data_t  rs485sensor_data;      //RS485总线传感器数据


#pragma pack(1)
uint8_t mpptCtrlr_CMD_Query[SOILSENSOR_NUMBR][SOILSENSOR_QUERYLEN]={
        {0x01, 0x03, 0x00, 0x00, 0x00, 0x08, 0x44, 0x0c},  /*4层土壤温湿度*/
        };    //query sensor for data via MODUBS
#pragma pack()

//---------------------------data type define-----------------
#pragma pack(1)      //声明按字节对齐
//--硕日 MPPT控制器 modbus

typedef struct
{
    uint8_t                 addr;                ///< modebusRTU device addr
    uint8_t                 functionCode;        ///< function code 0x03 0x04
    uint8_t                 len;                 ///< payload length

} modbusHead_t;



typedef struct
{

  modbusHead_t head;            //MODBUS head

  uint16_t LV1_humiX10;      //soil humidity
  uint16_t LV1_tempX10;      //soil TEMP

  uint16_t LV2_humiX10;      //soil humidity
  uint16_t LV2_tempX10;      //soil TEMP

  uint16_t LV3_humiX10;      //soil humidity
  uint16_t LV3_tempX10;      //soil TEMP

  uint16_t LV4_humiX10;      //soil humidity
  uint16_t LV4_tempX10;      //soil TEMP


  uint16_t checkSum;            //crc

}soilHumidity_dataFrame_t;



#pragma pack()




/**
  * @brief modebus ACK接收回调函数
  *
  * @param  rt_device_t rs485_dev:RS485设备指针     rt_size_t size接收到的缓存数据大小
  * @retval 错误代码始终返回RT_EOK
  */
static uint8_t rs485_rx_buf[RS485_RX_BUF_LEN];           //rs485 receive buffer

static rt_err_t rs485_rx_ind(rt_device_t rs485_dev, rt_size_t size)
{
 uint32_t rx_read_size = 0;



 memset(rs485_rx_buf,0,sizeof(rs485_rx_buf));
 if(rs485_dev != RT_NULL){
     rx_read_size = rt_device_read(rs485_dev, RT_NULL, rs485_rx_buf,size);
 }


 ulog_hex("rs485RxBuf: ", 64, rs485_rx_buf, rx_read_size);
 //--------数据校验: ID=3 功能码=03- 土壤温湿度 ------
 soilHumidity_dataFrame_t x_soilHumiFrame = {};       //MODBUS RX Frame data
 if(rs485_rx_buf[0] == 0x01 && rs485_rx_buf[1] == 0x03 && rs485_rx_buf[2] == 0x10){
   memcpy((void*)&x_soilHumiFrame,rs485_rx_buf,sizeof(x_soilHumiFrame));
   rs485sensor_data.LV1_soil_temp = __builtin_bswap16(x_soilHumiFrame.LV1_tempX10)*0.1;
   rs485sensor_data.LV1_soil_humi = __builtin_bswap16(x_soilHumiFrame.LV1_humiX10)*0.1;

   rs485sensor_data.LV2_soil_temp = __builtin_bswap16(x_soilHumiFrame.LV2_tempX10)*0.1;
   rs485sensor_data.LV2_soil_humi = __builtin_bswap16(x_soilHumiFrame.LV2_humiX10)*0.1;

   rs485sensor_data.LV3_soil_temp = __builtin_bswap16(x_soilHumiFrame.LV3_tempX10)*0.1;
   rs485sensor_data.LV3_soil_humi = __builtin_bswap16(x_soilHumiFrame.LV3_humiX10)*0.1;

   rs485sensor_data.LV4_soil_temp = __builtin_bswap16(x_soilHumiFrame.LV4_tempX10)*0.1;
   rs485sensor_data.LV4_soil_humi = __builtin_bswap16(x_soilHumiFrame.LV4_humiX10)*0.1;


 }

#if WDT_EN
   if(g_wdt_feed_cnt>0){
       FEED_WDT;                        //收到server读请求包或者控制命令，喂狗
       g_wdt_feed_cnt--;                //看门狗 30秒 重启，需在lora层喂狗，在MODBUS RTU请求数据命令收到后充值此计数器
   }
   else{
       rt_hw_cpu_reset();               //reboot mcu

   }
   log_i("watch dog counter = %d",g_wdt_feed_cnt);

#endif


// //--------数据校验: ID=6 功能码=03- 空气温湿度 ------
// airHumidity_dataFrame_t x_airHumiFrame;
// if(rs485_rx_buf[0] == 0x06 && rs485_rx_buf[1] == 0x03 && rs485_rx_buf[2] == 0x04){
//   memcpy((void*)&x_airHumiFrame,rs485_rx_buf,sizeof(x_airHumiFrame));
//   rs485sensor_data.air_temp = __builtin_bswap16(x_airHumiFrame.temp)*0.1;
//   rs485sensor_data.air_humi = __builtin_bswap16(x_airHumiFrame.humi)*0.1;
// }
// //--------数据校验: ID=10 功能码=03- 光照------
// lightStrength_dataFrame_t x_lightStrength;
//  if(rs485_rx_buf[0] == 0x0A && rs485_rx_buf[1] == 0x03 && rs485_rx_buf[2] == 0x04){
//    memcpy((void*)&x_lightStrength,rs485_rx_buf,sizeof(x_lightStrength));
//    rs485sensor_data.light_strength = __builtin_bswap32(x_lightStrength.lightStrength);
//
//  }
//  //--------数据校验: ID=9 功能码=03- CO2------
//  CO2_dataFrame_t x_CO2_concentration;
//   if(rs485_rx_buf[0] == 0x09 && rs485_rx_buf[1] == 0x04 && rs485_rx_buf[2] == 0x02){
//     memcpy((void*)&x_CO2_concentration,rs485_rx_buf,sizeof(x_CO2_concentration));
//     rs485sensor_data.air_co2 = __builtin_bswap16(x_CO2_concentration.CO2_concentration);
//
//   }

 return RT_EOK;
}

/**
  * @brief modebus 数据请求线程
  *
  * @param  void *RS485_uartPort
  * @retval void
  */



static void get_RS485data_entry(void * RS485_uartPort)
{
    uint8_t tx_index = 0;              //mpptCtrlr_CMD_Query命令数组的命令索引(行号)

    uint8_t tx_len = 0;
    rt_device_t rs485_dev;             /* 串口设备句柄 */
    struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;  /* 初始化配置参数 */

    rt_err_t open_result = RT_EOK;
    /* step1：查找串口设备 */
    rs485_dev = rt_device_find(RS485_uartPort);
    if (rs485_dev != RT_NULL)
    {
        /* step2：修改串口配置参数 */
        config.baud_rate = BAUD_RATE_4800;        //修改波特率为 9600
        config.data_bits = DATA_BITS_8;           //数据位 8
        config.stop_bits = STOP_BITS_1;           //停止位 1
        config.bufsz     = 128;                   //修改缓冲区 buff size 为 128
        config.parity    = PARITY_NONE;           //无奇偶校验位

        /* step3：控制串口设备。通过控制接口传入命令控制字，与控制参数 */
        rt_device_control(rs485_dev, RT_DEVICE_CTRL_CONFIG, &config);
        /* step4： 打开串口 */
        open_result = rt_device_open(rs485_dev, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_DMA_RX);
        /* using interrupt mode when DMA mode not supported */
        if (open_result == -RT_EIO)
        {
           open_result = rt_device_open(rs485_dev, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX);
        }
        RT_ASSERT(open_result == RT_EOK);

        rt_device_set_rx_indicate(rs485_dev, rs485_rx_ind);
    }
#if RS485_AUTO_DIR_CTRL
    rt_pin_mode(RS485_TXEN_PIN, PIN_MODE_OUTPUT);   //intialize the RS485_TXEN_PIN as output push-pull mode
#endif

    while (1)
    {

#if RS485_AUTO_DIR_CTRL
     RS485_TXEN;
#endif
     rt_thread_delay(300);
     if(rs485_dev != RT_NULL){
      tx_len = rt_device_write(rs485_dev, RT_NULL, mpptCtrlr_CMD_Query[(tx_index++)%SOILSENSOR_NUMBR], SOILSENSOR_QUERYLEN);
     }
#if RS485_AUTO_DIR_CTRL
     RS485_RXEN;
#endif
     tx_len = tx_len;

     rt_thread_mdelay(RS485_SAMPLE_CYCLE);         //RS485数据采集

     log_i("TEMP = (%d,%d,%d,%d)\r\n",   (uint8_t)rs485sensor_data.LV1_soil_temp,
                                         (uint8_t)rs485sensor_data.LV2_soil_temp,
                                         (uint8_t)rs485sensor_data.LV3_soil_temp,
                                         (uint8_t)rs485sensor_data.LV4_soil_temp );
     log_i("HUMI = (%d,%d,%d,%d)\r\n",   (uint8_t)rs485sensor_data.LV1_soil_humi,
                                         (uint8_t)rs485sensor_data.LV2_soil_humi,
                                         (uint8_t)rs485sensor_data.LV3_soil_humi,
                                         (uint8_t)rs485sensor_data.LV4_soil_humi );
    }
}



//===================THREAD CREATION===================
int modbus485_init(void)
{
    //---------local variables----------

    rt_thread_t  modbus485_thread;

    //-----------外设接口初始化----------------


    //---------------IPC------------
    /* 初始化事件对象 */
    /* 创建一个名为  modbus485 的线程，读取RS485 数据*/
    modbus485_thread = rt_thread_create("modbus485",
                                      get_RS485data_entry,
                                      "uart3",
                                      1024,
                                      RT_THREAD_PRIORITY_MAX -2,
                                      20);
      if (modbus485_thread != RT_NULL)
      {
        rt_thread_startup(modbus485_thread);
      }


    return RT_EOK;
}





